home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Add-Ons / After Dark / Refractor 1.0 / Source / Refractor.cp < prev    next >
Encoding:
Text File  |  1995-11-05  |  24.3 KB  |  1,005 lines  |  [TEXT/CWIE]

  1. //////////
  2. //
  3. //    Refractor 1.0
  4. //    ©1995 Steven J. Bushell
  5. //
  6. //    Refractor displays a moving circle of translated pixels
  7. //    around the desktop, giving the appearance of a refractive
  8. //    objects of different shapes floating through the air.
  9. //
  10. //    To keep the speed of the animation high, the pixel
  11. //    translations are precalculated and stored in an array
  12. //    of offsets.  The only calculation that is truly done
  13. //    on the fly is finding the new offset pixels from a pair
  14. //    of precomputed offsets in the X,Y plane.
  15. //
  16. //    The motion portions of this code, as well as the basic
  17. //    framework, are based loosely on "Bouncing Ball", by
  18. //    Patrick C. Beard and Bruce Burkhalter.  Bouncing Ball
  19. //    is distributed as sample code on the Code Warrior 7.0
  20. //    CD-ROM.  The rest of the code is copyright Steven J. Bushell,
  21. //    all rights reserved.
  22. //
  23. //    Oh yeah - although I am loathe to admit it, the idea for
  24. //    this module originally came from Windows 95.
  25. //
  26. //////////
  27.  
  28. #include "GraphicsModule_Types.h"
  29. #include "Refractor.h"
  30. #include <math.h>
  31.  
  32. //    The real meat.
  33. void    OffsetBits (RStoragePtr rStorage, PixMapHandle, PixMapHandle, Rect *);
  34. void    InitializeOffsetBuffer (RStoragePtr rStorage, GMParamBlockPtr params);
  35.  
  36. //    Offscreen support routines.
  37. PixMapHandle    BeginOffscreenDrawing (RStoragePtr rStorage, GWorldPtr world);
  38. PixMapHandle    HoldOffscreenPix (RStoragePtr rStorage, GWorldPtr world);
  39. void            ReleaseOffscreenPix (RStoragePtr rStorage);
  40. void            EndOffscreenDrawing (RStoragePtr rStorage);
  41.  
  42. //    Utility routines.
  43. short    random (short lower, short upper);
  44. void    CleanUp (RStorage** storage);
  45. Fixed    RandomAngle (short lower, short upper);
  46. void    WatchCursor (void);
  47.  
  48. static Boolean DemoMode (GMParamBlockPtr params)
  49. {
  50.     //    If the demo rect area isn't empty, we're in demo mode.
  51.  
  52.     return !EmptyRect (¶ms -> demoRect);
  53. }
  54.  
  55. static void SetRandomDirection (RStoragePtr rStorage)
  56. {
  57.     rStorage -> travelAngle = RandomAngle (10, 80);
  58.     rStorage -> travelSin = Frac2Fix (FracSin (rStorage -> travelAngle));
  59.     rStorage -> travelCos = Frac2Fix (FracCos (rStorage -> travelAngle));
  60. }
  61.  
  62. static void TravelToSlopRect (RStoragePtr rStorage)
  63. {
  64.     rStorage -> slopRect = rStorage -> travelRect;
  65.     InsetRect (&rStorage -> slopRect, - maxSlopSize, - maxSlopSize);
  66. }
  67.  
  68. OSErr DoInitialize (Handle *storage, RgnHandle /*blankRgn*/, GMParamBlockPtr params)
  69. {
  70.     Handle        h;
  71.     RStoragePtr    rStorage;
  72.     StringPtr    errStr;
  73.     StringPtr    unkErrStr = "\pRefractor: Sorry, this module cannot run on this machine.";
  74.     StringPtr    procErrStr = "\pRefractor: Sorry, a 68020 or later processor is required to run this module.";
  75.     StringPtr    sysVErrStr = "\pRefractor: Sorry, System 7 or later is required to run this module.";
  76.     StringPtr    mmErrStr = "\pRefractor:  Sorry, this module does not run under MultiModule.";
  77.     StringPtr    colorQDErrStr = "\pRefractor:  Sorry, Color Quickdraw must be present to run this module.";
  78.     StringPtr    memErrStr = "\pRefractor:  Sorry, out of memory.  Please make the size smaller.";
  79.     StringPtr    demoErrStr = "\pRefractor:  Sorry, not enough memory to run in demo mode.";
  80.     
  81.     *storage = nil;
  82.     
  83.     do
  84.     {
  85.         //    if color quickdraw is not available, chastise user.
  86.         if (!params -> colorQDAvail)
  87.         {
  88.             errStr = colorQDErrStr;
  89.             break;
  90.         }
  91.  
  92. #if !powerc
  93.         //    If we're not on at least a 68020 with System 7, get the hell out.
  94.         //    PowerPC code always has this requirement satisfied
  95.         //    so we only compile it for 68k.
  96.         //    (Gestalt glue is supplied in MacOS.lib.)
  97.         long    result;
  98.         OSErr    err = Gestalt (gestaltProcessorType, &result);
  99.         if (err != noErr)
  100.         {
  101.             errStr = unkErrStr;
  102.             break;
  103.         }
  104.  
  105.         if ((result == gestalt68000) || (result == gestalt68010))
  106.         {
  107.             errStr = procErrStr;
  108.             break;
  109.         }
  110.  
  111.         err = Gestalt (gestaltSystemVersion, &result);
  112.         if (err != noErr)
  113.         {
  114.             errStr = unkErrStr;
  115.             break;
  116.         }
  117.  
  118.         if (result < 0x0700L)
  119.         {
  120.             errStr = sysVErrStr;
  121.             break;
  122.         }
  123. #endif
  124.  
  125.         //    We don't allow MultiModule operation
  126.         //    because we don't work correctly in it.
  127.         //    (Because AD doesn't set up the blankRegion correctly
  128.         //    during MultiModule.)
  129.         if (params -> systemConfig & MultiModuleRunning)
  130.         {
  131.             errStr = mmErrStr;
  132.             break;
  133.         }
  134.  
  135.         //    Create handle to hold all our goodies.
  136.         h = NewHandleClear (sizeof(RStorage));
  137.         if (!h)
  138.         {
  139.             errStr = memErrStr;
  140.             break;
  141.         }
  142.     
  143.         //    store a reference to our storage where AD can keep it.
  144.         *storage = h;    
  145.         
  146.         //    Lock handle while it's being used.
  147.         HLockHi (h);    
  148.         rStorage = (RStoragePtr)*h;
  149.         
  150.         //    Get the size from the second slider in the ui.
  151.         long    boxSize = (params -> controlValues[1] * maxBoxSize) / 100;
  152.         if (boxSize < 16)
  153.             boxSize = 16;
  154.         rStorage -> travelRect.right = rStorage -> travelRect.left + boxSize;
  155.         rStorage -> travelRect.bottom = rStorage -> travelRect.top + boxSize;
  156.     
  157.         //    Set up basic Rects.
  158.         long    allocSize = DemoMode (params) ? maxBoxSize : boxSize;
  159.         SetRect (&rStorage -> travelRect, 0, 0, allocSize, allocSize);
  160.         TravelToSlopRect (rStorage);
  161.         rStorage -> oldSlopRect = rStorage -> slopRect;
  162.  
  163.         //    Allocate GWorlds.
  164.         QDErr    qdErr;
  165.         qdErr = NewGWorld (&rStorage -> srcWorld, 32, &rStorage -> slopRect, nil, nil, 0);
  166.         if (!rStorage -> srcWorld || qdErr)
  167.         {
  168.             qdErr = NewGWorld (&rStorage -> srcWorld, 32, &rStorage -> slopRect, nil, nil, useTempMem);
  169.             if (!rStorage -> srcWorld || qdErr)
  170.             {
  171.                 errStr = DemoMode (params) ? demoErrStr : memErrStr;
  172.                 break;
  173.             }
  174.         }
  175.  
  176.         qdErr = NewGWorld (&rStorage -> dstWorld, 32, &rStorage -> slopRect, nil, nil, 0);
  177.         if (!rStorage -> dstWorld || qdErr)
  178.         {
  179.             qdErr = NewGWorld (&rStorage -> dstWorld, 32, &rStorage -> slopRect, nil, nil, useTempMem);
  180.             if (!rStorage -> dstWorld || qdErr)
  181.             {
  182.                 errStr = DemoMode (params) ? demoErrStr : memErrStr;
  183.                 break;
  184.             }
  185.         }
  186.  
  187.         //    Allocate offset buffer.
  188.         rStorage -> offsetBuffer = NewHandleClear (allocSize * allocSize * sizeof (short) * 2L);
  189.         if (!rStorage -> offsetBuffer)
  190.         {
  191.             errStr = DemoMode (params) ? demoErrStr : memErrStr;
  192.             break;
  193.         }
  194.         HLock (rStorage -> offsetBuffer);
  195.  
  196.         rStorage -> drawRgn = NewRgn ();
  197.         if (!rStorage -> drawRgn)
  198.         {
  199.             errStr = DemoMode (params) ? demoErrStr : memErrStr;
  200.             break;
  201.         }
  202.  
  203.         rStorage -> oldDrawRgn = NewRgn ();
  204.         if (!rStorage -> oldDrawRgn)
  205.         {
  206.             errStr = DemoMode (params) ? demoErrStr : memErrStr;
  207.             break;
  208.         }
  209.  
  210.         //    Set up initial conditions.
  211.         SetRect (&rStorage -> travelRect, 0, 0, boxSize, boxSize);
  212.         OffsetRect (&rStorage -> travelRect, maxSlopSize, maxSlopSize);
  213.         TravelToSlopRect (rStorage);
  214.         rStorage -> oldSlopRect = rStorage -> slopRect;
  215.         
  216.         rStorage -> hDir = 1;
  217.         rStorage -> vDir = 1;
  218.         SetRandomDirection (rStorage);
  219.  
  220.         rStorage -> timeToReselect = 0;
  221.         rStorage -> needToUpdate = 0;
  222.         rStorage -> lastTouch = 0UL;
  223.         rStorage -> timeToChange = 0;
  224.  
  225.         {
  226.             //    Initialize Source GWorld.
  227.             PixMapHandle    gwPmh;
  228.             gwPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
  229.             if (gwPmh)
  230.             {
  231.                 SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
  232.                 CopyBits (¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
  233.                             (BitMapPtr)*gwPmh,
  234.                             &rStorage -> slopRect,
  235.                             &rStorage -> slopRect,
  236.                             srcCopy, nil);
  237.             }
  238.  
  239.             EndOffscreenDrawing (rStorage);
  240.         }
  241.  
  242.         {
  243.             //    Initialize style selection and offset buffer.
  244.             short    style = params -> controlValues[2];
  245.             rStorage -> refractorStyle = style;
  246.             InitializeOffsetBuffer (rStorage, params);
  247.         }
  248.     
  249.         //    unlock storage handle.
  250.         HUnlock(h);
  251.  
  252.         //    Success!    
  253.         return noErr;
  254.  
  255.     } while (false);
  256.  
  257.     //    If we're here, something went wrong.  Clean up and get out.
  258.     BlockMove (errStr, params -> errorMessage, errStr[0] + 1);
  259.     CleanUp ((RStorageHandle)*storage);
  260.     SysBeep (0);
  261.  
  262.     return ModuleError;
  263. }
  264.  
  265. //    Recovery zone - called if anything fails.
  266. void CleanUp (RStorage **storage)
  267. {
  268.     if (storage)
  269.     {
  270.         RStorage    *rStorage;
  271.         
  272.         HLock((Handle)storage);
  273.         rStorage = *storage;
  274.  
  275.         if (rStorage -> srcWorld)
  276.         {
  277.             DisposeGWorld (rStorage -> srcWorld);
  278.             rStorage -> srcWorld = nil;
  279.         }
  280.  
  281.         if (rStorage -> dstWorld)
  282.         {
  283.             DisposeGWorld (rStorage -> dstWorld);
  284.             rStorage -> dstWorld = nil;
  285.         }
  286.  
  287.         if (rStorage -> offsetBuffer)
  288.         {
  289.             DisposeHandle (rStorage -> offsetBuffer);
  290.             rStorage -> offsetBuffer = nil;
  291.         }
  292.  
  293.         if (rStorage -> drawRgn)
  294.         {
  295.             DisposeRgn (rStorage -> drawRgn);
  296.             rStorage -> drawRgn = nil;
  297.         }
  298.  
  299.         if (rStorage -> oldDrawRgn)
  300.         {
  301.             DisposeRgn (rStorage -> oldDrawRgn);
  302.             rStorage -> oldDrawRgn = nil;
  303.         }
  304.  
  305.         DisposHandle((Handle)storage);
  306.     }
  307. }
  308.  
  309. //    Hereafter we can safely assume we're on a 68020 or better.
  310. #if !powerc
  311.     #pragma code68020 on
  312. #endif
  313.  
  314. OSErr DoBlank (Handle /*storage*/, RgnHandle /*blankRgn*/, GMParamBlockPtr params)
  315. {
  316.     long    brightness = (params -> controlValues[3] * 256) / 100;
  317.  
  318.     params -> brightness = brightness;
  319.  
  320.     return noErr;
  321. }
  322.  
  323. OSErr DoDrawFrame (Handle storage, RgnHandle blankRgn ,GMParamBlockPtr params)
  324. {
  325.     RStoragePtr rStorage;    //    to hold dereferenced storage handle
  326.     
  327.     //    lock our storage down so we can dereference it for faster access
  328.     HLock (storage);
  329.     rStorage = (RStoragePtr) *storage;
  330.  
  331.     //    This is all that's necessary to control the brightness slider.
  332.     long    brightness = (params -> controlValues[3] * 256) / 100;
  333.     params -> brightness = brightness;
  334.  
  335.     //    Get the size from the second slider in the ui.
  336.     //    Check it agains the current setting to see if we need resizing.
  337.     long    boxSize = (params -> controlValues[1] * maxBoxSize) / 100;
  338.  
  339.     //    Don't let it get too small.
  340.     if (boxSize < 16)
  341.         boxSize = 16;
  342.  
  343.     if (boxSize != rStorage -> travelRect.right - rStorage -> travelRect.left)
  344.     {
  345.         rStorage -> lastTouch = TickCount ();
  346.  
  347.         if (rStorage -> needToUpdate == 0)
  348.         {
  349.             //    The size has changed so put the original screen bits back.
  350.             PixMapHandle    srcPmh;
  351.             srcPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
  352.             if (srcPmh)
  353.             {
  354.                 EndOffscreenDrawing (rStorage);
  355.                 if (LockPixels (srcPmh))
  356.                 {
  357.                     CopyBits ((BitMapPtr)*srcPmh,
  358.                                 ¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
  359.                                 &rStorage -> slopRect,
  360.                                 &rStorage -> slopRect,
  361.                                 srcCopy, blankRgn);
  362.                     UnlockPixels (srcPmh);
  363.                 }
  364.             }
  365.         }
  366.  
  367.         //    Flag a size update for the next time through.
  368.         //    (It's not done immediately so the user can
  369.         //    move the slider smoothly.)
  370.         rStorage -> needToUpdate = 1;
  371.  
  372.         //    Set the new size.
  373.         rStorage -> travelRect.right = rStorage -> travelRect.left + boxSize;
  374.         rStorage -> travelRect.bottom = rStorage -> travelRect.top + boxSize;
  375.  
  376.         //    See if we're going to hang out of our drawing region.
  377.         Rect    bBox = (*blankRgn) -> rgnBBox;
  378.         Rect    newRect = rStorage -> travelRect;
  379.         
  380.         //    If we are hanging out, put us back in.
  381.         if (newRect.bottom > bBox.bottom)
  382.         {
  383.             OffsetRect (&rStorage -> travelRect, 0, bBox.bottom - newRect.bottom);
  384.         }
  385.  
  386.         if (newRect.right > bBox.right)
  387.         {
  388.             OffsetRect (&rStorage -> travelRect, bBox.right - newRect.right, 0);
  389.         }
  390.  
  391.         TravelToSlopRect (rStorage);
  392.         rStorage -> oldSlopRect = rStorage -> slopRect;
  393.         HUnlock (storage);
  394.         return noErr;
  395.     }
  396.  
  397.     //    Do the flagged update.
  398.     if (rStorage -> needToUpdate)
  399.     {
  400.         //    But only if a half-second has gone by.
  401.         //    This is the key to the smooth slider action.
  402.         if (TickCount () - rStorage -> lastTouch > 30UL)
  403.         {
  404.             //    Reset for next resize.
  405.             rStorage -> lastTouch = 0UL;
  406.             InitializeOffsetBuffer (rStorage, params);
  407.             rStorage -> needToUpdate = 0;
  408.     
  409.             {
  410.                 //    Copy bits from screen into screen buffer.
  411.                 PixMapHandle    gwPmh;
  412.                 gwPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
  413.                 if (gwPmh)
  414.                 {
  415.                     SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
  416.                     CopyBits (¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
  417.                                 (BitMapPtr)*gwPmh,
  418.                                 &rStorage -> slopRect,
  419.                                 &rStorage -> slopRect,
  420.                                 srcCopy, blankRgn);
  421.                 }
  422.     
  423.                 EndOffscreenDrawing (rStorage);
  424.             }
  425.         }
  426.         else
  427.         {
  428.             HUnlock (storage);
  429.             return noErr;
  430.         }
  431.     }
  432.  
  433.     //    Reinitialize offset buffer if the popup has changed,
  434.     //    or if we've rebounded 12 times.
  435.     short    style = params -> controlValues[2];
  436.     if ((style != rStorage -> refractorStyle)
  437.         || ((rStorage -> refractorStyle == 1) && (rStorage -> timeToReselect >= 12)))
  438.     {
  439.         rStorage -> timeToReselect = 0;
  440.         rStorage -> refractorStyle = style;
  441.         InitializeOffsetBuffer (rStorage, params);
  442.     }
  443.  
  444.     //    And now for the actual animation...
  445.     
  446.     //    Get the source world PixMap.
  447.     PixMapHandle    srcPmh, dstPmh;
  448.     srcPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
  449.     if (srcPmh)
  450.     {
  451.         EndOffscreenDrawing (rStorage);
  452.         if (LockPixels (srcPmh))
  453.         {
  454.             dstPmh = BeginOffscreenDrawing (rStorage, rStorage -> dstWorld);
  455.             if (dstPmh)
  456.             {
  457.                 //    Copy the pixels from the screen buffer to the drawing buffer.
  458.                 SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
  459.                 RectRgn (rStorage -> drawRgn, &rStorage -> slopRect);
  460.                 RectRgn (rStorage -> oldDrawRgn, &rStorage -> travelRect);
  461.                 XorRgn (rStorage -> drawRgn, rStorage -> oldDrawRgn, rStorage -> drawRgn);
  462.                 CopyBits (    (BitMapPtr)*srcPmh,
  463.                             (BitMapPtr)*dstPmh,
  464.                             &rStorage -> slopRect,
  465.                             &rStorage -> slopRect,
  466.                             srcCopy, rStorage -> drawRgn);
  467.  
  468.                 //    Move those pixels around!
  469.                 OffsetBits (rStorage,
  470.                             srcPmh,
  471.                             dstPmh,
  472.                             &rStorage -> travelRect);
  473.             }
  474.             
  475.             EndOffscreenDrawing (rStorage);
  476.         }
  477.     
  478.         UnlockPixels (srcPmh);
  479.     
  480.         //    Spit the results back to the screen.
  481.         if (LockPixels (dstPmh))
  482.         {
  483.             CopyBits ((BitMapPtr)*dstPmh,
  484.                         ¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
  485.                         &rStorage -> slopRect,
  486.                         &rStorage -> slopRect,
  487.                         srcCopy, blankRgn);
  488.             UnlockPixels (dstPmh);
  489.         }
  490.     
  491.         //    Pick a new direction if we've rebounded 8 times.
  492.         if (rStorage -> timeToChange > 8)
  493.         {
  494.             rStorage -> timeToChange = 0;
  495.             SetRandomDirection (rStorage);
  496.         }
  497.     
  498.         //    Calc x and y components of velocity.
  499.         Fixed    speed = Long2Fix (params -> controlValues[0]);
  500.         long    hSpeed = Fix2Long (FixMul (speed, rStorage -> travelCos));
  501.         long    vSpeed = Fix2Long (FixMul (speed, rStorage -> travelSin));
  502.     
  503.         hSpeed = (hSpeed * rStorage -> hDir * maxSlopSize) / 100;
  504.         vSpeed = (vSpeed * rStorage -> vDir * maxSlopSize) / 100;
  505.     
  506.         rStorage -> oldSlopRect = rStorage -> slopRect;
  507.     
  508.         //    Try to move box to new location.
  509.         Rect    bBox = (*blankRgn) -> rgnBBox;
  510.         Rect    newRect = rStorage -> travelRect;
  511.         OffsetRect (&newRect, hSpeed, vSpeed);
  512.  
  513.         //    Take care of wall collisions.
  514.         if ((newRect.top < bBox.top) || (newRect.bottom > bBox.bottom))
  515.         {
  516.             rStorage -> vDir = - rStorage -> vDir;
  517.             vSpeed = - vSpeed;
  518.             rStorage -> timeToChange ++;
  519.             rStorage -> timeToReselect ++;
  520.         }
  521.     
  522.         if ((newRect.left < bBox.left) || (newRect.right > bBox.right))
  523.         {
  524.             rStorage -> hDir = - rStorage -> hDir;
  525.             hSpeed = - hSpeed;
  526.             rStorage -> timeToChange ++;
  527.             rStorage -> timeToReselect ++;
  528.         }
  529.  
  530.         //    Register the movement.    
  531.         OffsetRect (&rStorage -> travelRect, hSpeed, vSpeed);
  532.         TravelToSlopRect (rStorage);
  533.         
  534.         //    Update the screen buffer.
  535.         srcPmh = BeginOffscreenDrawing (rStorage, rStorage -> srcWorld);
  536.         if (srcPmh)
  537.         {
  538.             SetOrigin (rStorage -> slopRect.left, rStorage -> slopRect.top);
  539.         
  540.             CopyBits ((BitMapPtr)*srcPmh,
  541.                         (BitMapPtr)*srcPmh,
  542.                         &rStorage -> slopRect,
  543.                         &rStorage -> oldSlopRect,
  544.                         srcCopy, nil);
  545.         
  546.             RectRgn (rStorage -> drawRgn, &rStorage -> slopRect);
  547.             RectRgn (rStorage -> oldDrawRgn, &rStorage -> oldSlopRect);
  548.             DiffRgn (rStorage -> drawRgn, rStorage -> oldDrawRgn, rStorage -> drawRgn);
  549.             
  550.             //    Don't try to copy from space outside of what AD tells us we can have.
  551.             SectRgn (blankRgn, rStorage -> drawRgn, rStorage -> drawRgn);
  552.             CopyBits (¶ms -> qdGlobalsCopy -> qdThePort -> portBits,
  553.                         (BitMapPtr)*srcPmh,
  554.                         &rStorage -> slopRect,
  555.                         &rStorage -> slopRect,
  556.                         srcCopy, rStorage -> drawRgn);
  557.         }
  558.     
  559.         EndOffscreenDrawing (rStorage);
  560.     }
  561.  
  562.     HUnlock (storage);
  563.  
  564.     return noErr;
  565. }
  566.  
  567. OSErr DoClose (Handle storage, RgnHandle /*blankRgn*/, GMParamBlockPtr /*params*/)
  568. {
  569.     RStorage    **rStorage = (RStorage **)storage;
  570.  
  571.     //    Clean up the mess we made.
  572.     CleanUp (rStorage);
  573.  
  574.     return noErr;
  575. }
  576.  
  577. OSErr DoSetUp (RgnHandle /*blankRgn*/, short message, GMParamBlockPtr /*params*/)
  578. {
  579.     //    DoSetUp is not needed.
  580.  
  581.     switch (message)
  582.     {
  583.         default:
  584.             break;
  585.     }
  586.  
  587.     return noErr;
  588. }
  589.  
  590. //    Cool Utes.
  591.  
  592. short random (short lower, short upper)
  593. {
  594.     //    A nice func to return a random short between lower and upper.
  595.     short    r = Random ();
  596.     
  597.     if (r < 0)
  598.         r = - r;
  599.  
  600.     return lower + r % (upper - lower + 1);
  601. }
  602.  
  603. Fixed RandomAngle (short lower, short upper)
  604. {
  605.     //    Returns in Fixed notation a random angle
  606.     //    between lower and upper (which are in degrees).
  607.     const Fixed    PI_OVER_4 = 0xC910L;    //    PI/4 expressed in fixed point.
  608.  
  609.     return FixDiv(FixMul(Long2Fix(random(lower, upper)), PI_OVER_4), Long2Fix(45));
  610. }
  611.  
  612. void WatchCursor (void)
  613. {
  614.     //    Sets the cursor to the watch.
  615.     CursHandle    cursor = GetCursor (watchCursor);
  616.  
  617.     if (cursor)
  618.     {
  619.         SetCursor (*cursor);
  620.         ReleaseResource ((Handle)cursor);
  621.     }
  622. }
  623.  
  624. //    Offscreen drawing utilities.
  625.  
  626. PixMapHandle
  627. BeginOffscreenDrawing (RStoragePtr rStorage, GWorldPtr world)
  628. {
  629.     //    Called to prepare a GWorld for drawing.
  630.     //    Should be followed by HoldOffscreenPix.
  631.  
  632.     GetGWorld (&rStorage -> savedCPort, &rStorage -> savedGDevice);
  633.     SetGWorld (world, nil);
  634.     
  635.     return HoldOffscreenPix (rStorage, world);
  636. }
  637.  
  638. PixMapHandle
  639. HoldOffscreenPix (RStoragePtr rStorage, GWorldPtr world)
  640. {
  641.     //    Locks the pixels in the given PixMap for drawing.
  642.  
  643.     rStorage -> worldPixels = GetGWorldPixMap (world);
  644.     
  645.     return (LockPixels (rStorage -> worldPixels))
  646.         ?    rStorage -> worldPixels
  647.         :    nil;
  648. }
  649.  
  650. void
  651. ReleaseOffscreenPix (RStoragePtr rStorage)
  652. {
  653.     //    Unlocks the pixels in the given PixMap.
  654.  
  655.     if (rStorage -> worldPixels)
  656.     {
  657.         UnlockPixels (rStorage -> worldPixels);
  658.         rStorage -> worldPixels = nil;
  659.     }
  660. }
  661.  
  662. void
  663. EndOffscreenDrawing (RStoragePtr rStorage)
  664. {
  665.     //    Indicates we're done drawing in this GWorld.
  666.  
  667.     ReleaseOffscreenPix (rStorage);
  668.     
  669.     SetGWorld (rStorage -> savedCPort, rStorage -> savedGDevice);
  670. }
  671.  
  672. void
  673. OffsetBits (RStoragePtr rStorage, PixMapHandle srcPmh, PixMapHandle dstPmh, Rect *r)
  674. {
  675.     //    The offset array contains pairs of short integers, one pair
  676.     //    for each pixel.  The pair represents an offset in the X and Y
  677.     //    direction where the pixel for a given location will come from.
  678.  
  679.     //    This routine runs through each offset pair in the array and
  680.     //    finds the appropriate pixel at that relative offset in the
  681.     //    source PixMap to put in the destination PixMap.
  682.  
  683.     long            srcRowBytes = (*srcPmh) -> rowBytes & 0x3fffL;
  684.     long            dstRowBytes = (*dstPmh) -> rowBytes & 0x3fffL;
  685.  
  686.     unsigned long     srcPixBuf = (unsigned long) GetPixBaseAddr (srcPmh);
  687.     unsigned long     dstPixBuf = (unsigned long) GetPixBaseAddr (dstPmh);
  688.  
  689.     //    Move pix pointers to the start of their data.
  690.     srcPixBuf += (r -> top - (*srcPmh) -> bounds.top) * srcRowBytes
  691.                 + (r -> left - (*srcPmh) -> bounds.left) * 4L;
  692.     dstPixBuf += (r -> top - (*dstPmh) -> bounds.top) * dstRowBytes
  693.                 + (r -> left - (*dstPmh) -> bounds.left) * 4L;
  694.  
  695.     short            *offsetArray = (short *)*rStorage -> offsetBuffer;
  696.     long            tileHeight = r -> bottom - r -> top;
  697.     long            tileWidth = r -> right - r -> left;
  698.  
  699.     unsigned long    srcPixPtr = srcPixBuf,
  700.                     dstPixPtr = dstPixBuf;
  701.     short            hOffset, vOffset;
  702.     long            pixel;
  703.  
  704.     for (long row = 0; row < tileHeight; row ++)
  705.     {
  706.         srcPixPtr = srcPixBuf;
  707.         dstPixPtr = dstPixBuf;
  708.  
  709.         for (long col = 0; col < tileWidth; col ++)
  710.         {
  711.             hOffset = *(offsetArray ++);
  712.             vOffset = *(offsetArray ++);
  713.  
  714.             pixel = *(long *)(srcPixPtr + vOffset * srcRowBytes + hOffset * 4);
  715.             *(long *)dstPixPtr = pixel;
  716.             
  717.             srcPixPtr += 4;
  718.             dstPixPtr += 4;
  719.         }
  720.  
  721.         srcPixBuf += srcRowBytes;
  722.         dstPixBuf += dstRowBytes;
  723.     }
  724. }
  725.  
  726. void
  727. InitializeOffsetBuffer (RStoragePtr rStorage, GMParamBlockPtr params)
  728. {
  729.     //    This routine calculates the values for the offset array,
  730.     //    which contains a pair of short integers for each pixel
  731.     //    that will be processed.
  732.     
  733.     //    Based on the popup selection, a different algorithm is used
  734.     //    to generate the offset pairs.
  735.  
  736.     short    style = rStorage -> refractorStyle;
  737.     Rect    r = rStorage -> travelRect;
  738.     short    *offsetArray;
  739.     long    width = r.right - r.left;
  740.     long    height = r.bottom - r.top;
  741.     long    numPixels = width * height;
  742.     long    row, col, hMid, vMid, x, y;
  743.     double    dist, xd, yd, angle;
  744.  
  745.     //    In case this takes a long time.
  746.     WatchCursor ();
  747.  
  748.     //    For easy access.
  749.     HLock (rStorage -> offsetBuffer);
  750.     offsetArray = (short *)*rStorage -> offsetBuffer;
  751.  
  752.     //    Random setting?
  753.     if (style == 1)
  754.     {
  755.         style = random (3, 10);
  756.     }
  757.  
  758.     //    The style value corresponds to the popup menu.
  759.     switch (style)
  760.     {
  761.         default:
  762.         case eWavyGravy:
  763.             for (row = 0; row < height; row ++)
  764.                 for (col = 0; col < width; col ++)
  765.                 {
  766.                     hMid = width / 2;
  767.                     vMid = height / 2;
  768.                     x = col - hMid;
  769.                     y = row - vMid;
  770.                     dist = sqrt (x * x + y * y);
  771.                     xd = x;
  772.                     yd = y;
  773.  
  774.                     if (dist < hMid)
  775.                     {
  776.                         angle = - acos (xd / dist);
  777.                         if (yd > 0)
  778.                             angle = - angle;
  779.                         angle += (hMid - dist) * 2 / hMid;
  780.  
  781.                         xd = cos (angle) * dist;
  782.                         yd = sin (angle) * dist;
  783.     
  784.                         x = xd + hMid;
  785.                         y = yd + vMid;
  786.                     }
  787.                     else
  788.                     {
  789.                         x = col;
  790.                         y = row;
  791.                     }
  792.  
  793.                     *(offsetArray ++) = x - col;
  794.                     *(offsetArray ++) = y - row;
  795.                 }
  796.             break;
  797.  
  798.         case eHurricane:
  799.             for (row = 0; row < height; row ++)
  800.                 for (col = 0; col < width; col ++)
  801.                 {
  802.                     hMid = width / 2;
  803.                     vMid = height / 2;
  804.                     x = col - hMid;
  805.                     y = row - vMid;
  806.                     dist = sqrt (x * x + y * y);
  807.                     xd = x;
  808.                     yd = y;
  809.  
  810.                     if (dist < hMid)
  811.                     {
  812.                         angle = - acos (xd / dist);
  813.                         if (yd > 0)
  814.                             angle = - angle;
  815.  
  816.                         angle += (hMid - dist) * (hMid - dist) / (hMid * sqrt(vMid));
  817.  
  818.                         xd = cos (angle) * dist;
  819.                         yd = sin (angle) * dist;
  820.     
  821.                         x = xd + hMid;
  822.                         y = yd + vMid;
  823.                     }
  824.                     else
  825.                     {
  826.                         x = col;
  827.                         y = row;
  828.                     }
  829.  
  830.                     *(offsetArray ++) = x - col;
  831.                     *(offsetArray ++) = y - row;
  832.                 }
  833.             break;
  834.  
  835.         case eFisheye:
  836.             for (row = 0; row < height; row ++)
  837.                 for (col = 0; col < width; col ++)
  838.                 {
  839.                     hMid = width / 2;
  840.                     vMid = height / 2;
  841.                     x = col - hMid;
  842.                     y = row - vMid;
  843.                     dist = sqrt (x * x + y * y) + 1;
  844.  
  845.                     if (dist < hMid)
  846.                     {
  847.                         x = x * sin ((pi * dist / 2) / hMid - pi / 2) / 1.25;
  848.                         y = y * sin ((pi * dist / 2) / hMid - pi / 2) / 1.25;
  849.                     }
  850.                     else
  851.                     {
  852.                         x = y = 0;
  853.                     }
  854.  
  855.                     *(offsetArray ++) = x;
  856.                     *(offsetArray ++) = y;
  857.                 }
  858.             break;
  859.  
  860.         case eWildDiffuser:
  861.             for (row = 0; row < height; row ++)
  862.                 for (col = 0; col < width; col ++)
  863.                 {
  864.                     hMid = width / 2;
  865.                     vMid = height / 2;
  866.                     x = col - hMid;
  867.                     y = row - vMid;
  868.                     dist = sqrt (x * x + y * y);
  869.  
  870.                     x = y = 0;
  871.                     if (dist < 1.0)
  872.                         dist = 1.0;
  873.                     short    prob = (hMid / 2) * 2;
  874.                     if (prob)
  875.                     {
  876.                         x = random (- prob, prob);
  877.                         y = random (- prob, prob);
  878.                         x /= dist;
  879.                         y /= dist;
  880.                     }
  881.  
  882.                     *(offsetArray ++) = x;
  883.                     *(offsetArray ++) = y;
  884.                 }
  885.             break;
  886.  
  887.         case eSpectacle:
  888.             for (row = 0; row < height; row ++)
  889.                 for (col = 0; col < width; col ++)
  890.                 {
  891.                     hMid = width / 2;
  892.                     vMid = height / 2;
  893.                     x = col - hMid;
  894.                     y = row - vMid;
  895.                     dist = sqrt (x * x + y * y) + 1;
  896.  
  897.                     if (dist < hMid)
  898.                     {
  899.                         x = x * cos ((pi * dist / 2) / hMid);
  900.                         y = y * cos ((pi * dist / 2) / hMid);
  901.                     }
  902.                     else
  903.                     {
  904.                         x = y = 0;
  905.                     }
  906.  
  907.                     *(offsetArray ++) = x;
  908.                     *(offsetArray ++) = y;
  909.                 }
  910.             break;
  911.  
  912.         case eMagnifier:
  913.             for (row = 0; row < height; row ++)
  914.                 for (col = 0; col < width; col ++)
  915.                 {
  916.                     hMid = width / 2;
  917.                     vMid = height / 2;
  918.                     x = (col - hMid);
  919.                     y = (row - vMid);
  920.                     dist = sqrt (x * x + y * y) + 1;
  921.  
  922.                     if (dist > hMid)
  923.                     {
  924.                         x = y = 0;
  925.                     }
  926.                     else
  927.                     {
  928.                         x = - (col - hMid) / 2;
  929.                         y = - (row - vMid) / 2;
  930.                     }
  931.  
  932.                     *(offsetArray ++) = x;
  933.                     *(offsetArray ++) = y;
  934.                 }
  935.             break;
  936.  
  937.         case eWormhole:
  938.             for (row = 0; row < height; row ++)
  939.                 for (col = 0; col < width; col ++)
  940.                 {
  941.                     hMid = width / 2;
  942.                     vMid = height / 2;
  943.                     x = col - hMid;
  944.                     y = row - vMid;
  945.                     dist = sqrt (x * x + y * y) + 1;
  946.  
  947.                     if (dist < hMid)
  948.                     {
  949.                         x = x * (hMid - fabs(x)) / dist;
  950.                         y = y * (hMid - fabs(y)) / dist;
  951.                     }
  952.                     else
  953.                     {
  954.                         x = y = 0;
  955.                     }
  956.  
  957.                     *(offsetArray ++) = x;
  958.                     *(offsetArray ++) = y;
  959.                 }
  960.             break;
  961.  
  962.         case eRipple:
  963.             for (row = 0; row < height; row ++)
  964.                 for (col = 0; col < width; col ++)
  965.                 {
  966.                     hMid = width / 2;
  967.                     vMid = height / 2;
  968.                     x = col - hMid;
  969.                     y = row - vMid;
  970.                     dist = sqrt (x * x + y * y);
  971.                     xd = x;
  972.                     yd = y;
  973.  
  974.                     if (dist < hMid)
  975.                     {
  976.                         angle = - acos (xd / dist);
  977.                         if (yd > 0)
  978.                             angle = - angle;
  979.  
  980.                         angle += sin ((2 * pi) * 5 * (hMid - dist) / hMid) / (2 * pi);
  981.  
  982.                         xd = cos (angle) * dist;
  983.                         yd = sin (angle) * dist;
  984.     
  985.                         x = xd + hMid;
  986.                         y = yd + vMid;
  987.                     }
  988.                     else
  989.                     {
  990.                         x = col;
  991.                         y = row;
  992.                     }
  993.  
  994.                     *(offsetArray ++) = x - col;
  995.                     *(offsetArray ++) = y - row;
  996.                 }
  997.             break;
  998.     }
  999.  
  1000.     HUnlock (rStorage -> offsetBuffer);
  1001.  
  1002.     //    Change back from the watch cursor.
  1003.     SetCursor (¶ms -> qdGlobalsCopy -> qdArrow);
  1004. }
  1005.